package it.unicam.fishpass.prism.editor;

import it.unicam.fishpass.prism.BasicGraphEditor;
import it.unicam.fishpass.prism.editor.EditorActions.ColorAction;
import it.unicam.fishpass.prism.editor.EditorActions.FontStyleAction;
import it.unicam.fishpass.prism.editor.EditorActions.HistoryAction;
import it.unicam.fishpass.prism.editor.EditorActions.KeyValueAction;
import it.unicam.fishpass.prism.editor.EditorActions.NewAction;
import it.unicam.fishpass.prism.editor.EditorActions.OpenAction;
import it.unicam.fishpass.prism.editor.EditorActions.PrintAction;
import it.unicam.fishpass.prism.editor.EditorActions.SaveAction;

import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.jws.soap.SOAPBinding.Style;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.JToolBar;
import javax.swing.SpinnerNumberModel;
import javax.swing.TransferHandler;

import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.util.mxGraphActions;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxResources;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;

public class EditorToolBar extends JToolBar {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8015443128436394471L;
	private final JSpinner maxTime;
	private final JButton button;
	/**
	 * 
	 * @param frame
	 * @param orientation
	 */
	private boolean ignoreZoomChange = false;
	private Action saveAction;

	/**
	 * 
	 */
	public EditorToolBar(final BasicGraphEditor editor, int orientation) {
		super(orientation);
		setBorder(BorderFactory.createCompoundBorder(
				BorderFactory.createEmptyBorder(3, 3, 3, 3), getBorder()));
		setFloatable(false);

		add(editor.bind("New", new NewAction(), "/images/new.gif"));
		add(editor.bind("Open", new OpenAction(), "/images/open.gif"));
		saveAction = editor.bind("Save", new SaveAction(false),
				"/images/save.gif");
		add(saveAction);

		addSeparator();

		add(editor.bind("Print", new PrintAction(), "/images/print.gif"));

		addSeparator();

		add(editor.bind("Cut", TransferHandler.getCutAction(),
				"/images/cut.gif"));
		add(editor.bind("Copy", TransferHandler.getCopyAction(),
				"/images/copy.gif"));
		add(editor.bind("Paste", TransferHandler.getPasteAction(),
				"/images/paste.gif"));

		addSeparator();

		add(editor.bind("Delete", mxGraphActions.getDeleteAction(),
				"/images/delete.gif"));

		addSeparator();

		add(editor.bind("Undo", new HistoryAction(true), "/images/undo.gif"));
		add(editor.bind("Redo", new HistoryAction(false), "/images/redo.gif"));

		// Gets the list of available fonts from the local graphics environment
		// and adds some frequently used fonts at the beginning of the list
		GraphicsEnvironment env = GraphicsEnvironment
				.getLocalGraphicsEnvironment();
		List<String> fonts = new ArrayList<String>();
		fonts.addAll(Arrays.asList(new String[] { "Helvetica", "Verdana",
				"Times New Roman", "Garamond", "Courier New", "-" }));
		fonts.addAll(Arrays.asList(env.getAvailableFontFamilyNames()));

		addSeparator();
		mxGraph graph = editor.getGraphComponent().getGraph();
		graph.setCellStyles(mxConstants.STYLE_FONTSIZE, "24");

		add(editor.bind("Left", new KeyValueAction(mxConstants.STYLE_ALIGN,
				mxConstants.ALIGN_LEFT), "/images/left.gif"));
		add(editor.bind("Center", new KeyValueAction(mxConstants.STYLE_ALIGN,
				mxConstants.ALIGN_CENTER), "/images/center.gif"));
		add(editor.bind("Right", new KeyValueAction(mxConstants.STYLE_ALIGN,
				mxConstants.ALIGN_RIGHT), "/images/right.gif"));

		addSeparator();

		add(editor.bind("Font", new ColorAction("Font",
				mxConstants.STYLE_FONTCOLOR), "/images/fontcolor.gif"));
		add(editor.bind("Stroke", new ColorAction("Stroke",
				mxConstants.STYLE_STROKECOLOR), "/images/linecolor.gif"));
		add(editor.bind("Fill", new ColorAction("Fill",
				mxConstants.STYLE_FILLCOLOR), "/images/fillcolor.gif"));

		addSeparator();

		final mxGraphView view = editor.getGraphComponent().getGraph()
				.getView();
		final JComboBox zoomCombo = new JComboBox(new Object[] { "400%",
				"200%", "150%", "100%", "75%", "50%", mxResources.get("page"),
				mxResources.get("width"), mxResources.get("actualSize") });
		zoomCombo.setEditable(true);
		zoomCombo.setMinimumSize(new Dimension(75, 0));
		zoomCombo.setPreferredSize(new Dimension(75, 0));
		zoomCombo.setMaximumSize(new Dimension(75, 100));
		zoomCombo.setMaximumRowCount(9);
		add(zoomCombo);

		// Sets the zoom in the zoom combo the current value
		mxIEventListener scaleTracker = new mxIEventListener() {
			/**
			 * 
			 */
			public void invoke(Object sender, mxEventObject evt) {
				ignoreZoomChange = true;

				try {
					zoomCombo.setSelectedItem((int) Math.round(100 * view
							.getScale()) + "%");
				} finally {
					ignoreZoomChange = false;
				}
			}
		};

		// Installs the scale tracker to update the value in the combo box
		// if the zoom is changed from outside the combo box
		view.getGraph().getView().addListener(mxEvent.SCALE, scaleTracker);
		view.getGraph().getView()
				.addListener(mxEvent.SCALE_AND_TRANSLATE, scaleTracker);

		// Invokes once to sync with the actual zoom value
		scaleTracker.invoke(null, null);

		zoomCombo.addActionListener(new ActionListener() {
			/**
			 * 
			 */
			public void actionPerformed(ActionEvent e) {
				mxGraphComponent graphComponent = editor.getGraphComponent();

				// Zoomcombo is changed when the scale is changed in the diagram
				// but the change is ignored here
				if (!ignoreZoomChange) {
					String zoom = zoomCombo.getSelectedItem().toString();

					if (zoom.equals(mxResources.get("page"))) {
						graphComponent.setPageVisible(true);
						graphComponent
								.setZoomPolicy(mxGraphComponent.ZOOM_POLICY_PAGE);
					} else if (zoom.equals(mxResources.get("width"))) {
						graphComponent.setPageVisible(true);
						graphComponent
								.setZoomPolicy(mxGraphComponent.ZOOM_POLICY_WIDTH);
					} else if (zoom.equals(mxResources.get("actualSize"))) {
						graphComponent.zoomActual();
					} else {
						try {
							zoom = zoom.replace("%", "");
							double scale = Math.min(16, Math.max(0.01,
									Double.parseDouble(zoom) / 100));
							graphComponent.zoomTo(scale,
									graphComponent.isCenterZoom());
						} catch (Exception ex) {
							JOptionPane.showMessageDialog(editor,
									ex.getMessage());
						}
					}
				}
			}
		});

		addSeparator();
		add(new JLabel("<html><b>Max time:</b></html>"));
		add(maxTime = new JSpinner(new SpinnerNumberModel(1, // initial value
				0, // min
				99999, // max
				1)));
		//
		button = new JButton("Generate!");
		button.addActionListener(new ActionListener() {
			private ActionEvent actionEvent;

			/**
			 * 
			 */
			public void actionPerformed(ActionEvent e) {
				if (editor.getCurrentFile() == null) // not saved ---> save!!!
					saveAction.actionPerformed(new ActionEvent(BasicGraphEditor
							.getGraphComponent(), 0, "Save"));
				//
				if (editor.getCurrentFile() != null) // have been saved now?
					editor.doInBackground();
			}
		});
		add(button);
	}

	public void setButtonStatus(boolean status) {
		button.setEnabled(status);
	}

	public String getMaxTime() {
		return maxTime.getValue().toString();
	}
}
